def decorator_test(fun):
    print("decorator func")

    def wrapper(*args, **kwargs):
        wrapper.co += 1  # 为函数属性加 1
        print("wrapper func")
        return fun(*args, **kwargs)

    wrapper.co = 0  # 新增了 wrapper 的函数属性
    return wrapper


@decorator_test
def fun():
    print("fun func")


a = decorator_test(fun)  # 在函数前面加上注解，实际上就是函数嵌套
# wrapper ，因为在 decorator_test里面，实际上返回了 wrapper，所以这里 a 的 name 就是 wrapper
print(a.__name__)

"""
@decorator_test
def fun():
    print("fun func")

上面这一段语句，就相当于：
fun = decorator_test(fun)
fun 作为变量带入到 decorator_test 函数，赋值给内部的局部变量 fun
然后新的 fun 就指向了 decorator_test(fun) 的返回，就是 wapper 函数
可以参考这篇文章：https://towardsdatascience.com/closures-and-decorators-in-python-2551abbc6eb6

"""

fun()  # decorator func;wrapper func; fun func
print(fun.__name__)  # wrapper ，这里 fun 指向了  wrapper
print(fun.co)  # 1, wrapper 函数属性在做注解的时候初始化为 0 。然后 fun指向 wrapper，wrapper 里面调用一次加
fun()
print(fun.co)  # 2
